#ifndef CONTACT_CONTACTMANAGER_H
#define CONTACT_CONTACTMANAGER_H


#include <QObject>
#include <QList>
#include <QMap>
#include <QMutex>
#include <QPointer>


namespace  Account {
class Member;
class User;
class Buddy;
}

namespace Contact {

class AbstractContact;
class PrivateContact;
class GroupContact;

class Manager : public QObject
{
    Q_OBJECT
public:
    typedef QList<AbstractContact *> ContactList;
    typedef QMap<qint64, AbstractContact *> ContactFinderMap;
    typedef ContactFinderMap::ConstIterator ItemFinderIterator;

private:
    Manager(QObject *parent = 0);
    ~Manager();

private:
    static Manager *m_instance;

private:
    mutable QMutex m_mutex;
    ContactList m_contactList;
    ContactFinderMap m_privateContactFinder;
    ContactFinderMap m_groupContactFinder;
    QPointer<AbstractContact> m_activeContact;


Q_SIGNALS:
    void contactAboutToBeAppended(AbstractContact *contact);
    void contactAppended(AbstractContact *contact);
    void contactAboutToBeRemoved(AbstractContact *contact);
    void contactRemoved(AbstractContact *contact);
    void contactAboutToBeUpdated(AbstractContact *contact);
    void contactUpdated(AbstractContact *contact);

Q_SIGNALS:
    void activeContactChanged(AbstractContact *contact);
    void lastContactTimeUpdated(AbstractContact *contact);
    void dataCleared();

private:
    void init();
    void setConnection() const;

    PrivateContact *createPrivateContact(const qint32 ownerId) const;
    GroupContact *createGroupContact(qint64 id) const;

private:
    void deleteContactList();
    void clearPrivateContactFinder();
    void clearGroupContactFinder();

private:
    void itemAboutToBeAppended(AbstractContact *contact);
    void itemAppended(AbstractContact *contact);
    void itemAboutToBeRemoved(AbstractContact *contact);
    void itemRemoved(AbstractContact *contact);
    void itemAboutToBeUpdated(AbstractContact *contact);
    void itemUpdated(AbstractContact *contact);

private slots:

    void onContactDataChanged(AbstractContact *contact);
    void onLastContactTimeUpdated(AbstractContact *contact);

public:
    static Manager *instance();

public:
    void clearData();

public:
    void append(AbstractContact *contact);
    void appendPrivateContact(AbstractContact *contact);
    void appendGroupContact(AbstractContact *contact);

    void insert(int position, AbstractContact *contact);
    void insertPrivateContact(int position, AbstractContact *contact);
    void insertGroupContact(int position, AbstractContact *contact);

    bool remove(AbstractContact *contact);

public:
    AbstractContact *findByIndex(int index) const;
    PrivateContact *findPrivateContactById(qint64 id) const;
    AbstractContact *findGroupContactById(qint64 id) const;
    AbstractContact *at(int index) const;

public:
    const ContactList &contacts() const;
    void setActiveContact(AbstractContact *contact);
    AbstractContact *activeContact() const;
    bool isActiveContact(AbstractContact *contact) const;

public:
    bool contains(AbstractContact *contact) const;
    bool containsPrivateContact(qint32 id) const;
    bool containsGroupContact(qint64 id) const;

    int count() const;
    int privateContactCount() const;
    int groupContactCount() const;

    int size() const;
    int privateContactSize() const;
    int groupContactSize() const;

    int indexOf(AbstractContact *contact) const;

public Q_SLOTS:
    void onActiveContactChanged(AbstractContact *contact);
};

} // namespace Contact

#endif // CONTACT_CONTACTMANAGER_H
